package com.uduemc.biso.node.web.api.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.uduemc.biso.core.extities.center.HostSetup;
import com.uduemc.biso.core.extities.center.Site;
import com.uduemc.biso.core.extities.node.custom.LoginNode;
import com.uduemc.biso.core.extities.node.custom.LoginNodeAgent;
import com.uduemc.biso.core.utils.JsonResult;
import com.uduemc.biso.core.utils.RedisUtil;
import com.uduemc.biso.core.utils.RestResult;
import com.uduemc.biso.node.core.entities.custom.LoginUser;
import com.uduemc.biso.node.core.feign.NodeHostFeign;
import com.uduemc.biso.node.core.feign.NodeSiteFeign;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.web.api.component.Identification;
import com.uduemc.biso.node.web.api.component.RequestHolder;
import com.uduemc.biso.node.web.api.service.LoginService;
import com.uduemc.biso.node.web.api.service.SiteService;
import com.uduemc.biso.node.web.component.CenterFunction;
import com.uduemc.biso.node.web.component.RedisKeyUtil;
import com.uduemc.biso.node.web.utils.IpUtil;
import com.uduemc.biso.node.web.utils.JwtTokenUtils;

import cn.hutool.core.util.URLUtil;

@Service
public class LoginServiceImpl implements LoginService {

	private static Logger logger = LoggerFactory.getLogger(LoginServiceImpl.class);

	@Autowired
	private ObjectMapper objectMapper;

	@Autowired
	private RedisUtil redisUtil;

	@Autowired
	private RedisKeyUtil redisKeyUtil;

	@Autowired
	private NodeHostFeign nodeHostFeign;

	@Autowired
	private NodeSiteFeign nodeSiteFeign;

	@Autowired
	private RequestHolder requestHolder;

	@Autowired
	private CenterFunction centerFunction;

	@Autowired
	private SiteService siteServiceImpl;

	@Autowired
	private GlobalProperties globalProperties;

	@Autowired
	private Identification identification;

	@Autowired
	private HttpServletRequest request;

	@Override
	public JsonResult tokenLogin(String token) {
		Map<String, String> param = new HashMap<>();
		param.put("token", token);
		String result = centerFunction.getNodeLoginForToken(param);
		if (!StringUtils.hasText(result)) {
			return JsonResult.noLogin("未能获取到 token，登录失败，请联系管理员！");
		}
		LoginNode loginNode = null;
		String jsessionid = null;
		try {
			loginNode = objectMapper.readValue(result, LoginNode.class);
			if (null == loginNode) {
				logger.error("获取 loginNode 信息未空！");
				return JsonResult.noLogin();
			}

			logger.info("LoginUserId: " + loginNode.getLoginUserId());
			logger.info("LoginUserName: " + loginNode.getLoginUserName());
			logger.info("LoginUserType: " + loginNode.getLoginUserType());
			logger.info("Host: " + loginNode.getHost().toString());
			logger.info("HostSetup: " + loginNode.getHostSetup().toString());
			logger.info("Sites: " + loginNode.getSites().toString());
			logger.info("Login35Mail: " + loginNode.getLogin35Mail());

			// 处理IP为 _ 的数据写入当前IP
			String ip = loginNode.getIp();
			if (ip.equals("_")) {
				loginNode.setIp(IpUtil.getIpAddr(request));
			}

			/**
			 * 对 host、host_setup、site 信息进行同步
			 */
			// 同步 host
			RestResult findOne = nodeHostFeign.findOne(loginNode.getHost().getId());
			if (findOne.getCode() == 200) {
				// 修改
				nodeHostFeign.updateById(loginNode.getHost());
			} else if (findOne.getCode() == 401) {
				// 添加
				nodeHostFeign.insert(loginNode.getHost());
			} else {
				// 同步信息出错
				logger.error("同步 Host 信息出错: " + findOne.toString());
			}
			// 验证 host_setup
			HostSetup hostSetup = loginNode.getHostSetup();
			if (hostSetup == null || hostSetup.getId() == null || hostSetup.getId().longValue() < 1) {
				// 获取到的信息中不包含 hostSetup 信息
				logger.error("未能获取到 hostSetup 信息!");
				return JsonResult.noLogin();
			}
			// 同步site
			synchroSites(loginNode.getSites());
			// 过滤删除状态
			List<Site> setInSite = new ArrayList<>();
			Long currentSiteId = 0L;
			for (Site site : loginNode.getSites()) {
				if (site.getStatus().shortValue() != (short) 4) {
					setInSite.add(site);
					if (currentSiteId < 1) {
						currentSiteId = site.getId();
					}
				}
			}
			loginNode.setSites(setInSite);

			// 检测是否初始化，如果没有初始化则初始化数据
			nodeHostFeign.init(loginNode.getHost().getId());

			// 重置缓存数据中的siteList
			siteServiceImpl.resetSiteList(loginNode.getHost().getId());

			// 获取默认站点
			Site defaultSite = siteServiceImpl.getDefaultSite(loginNode.getHost().getId());

			/**
			 * 生成 redisKey，jsessionid 存放在缓存中
			 */
			String sessionKey = redisKeyUtil.getLoginUserRedisKey(loginNode);
			String redisKey = globalProperties.getNodeRedisKey().makeNodeRedisKey(sessionKey);
			jsessionid = JwtTokenUtils.createToken(sessionKey, true);

			loginNode.setJsessionid(jsessionid);
			loginNode.setCurrentSiteId(defaultSite == null ? currentSiteId : defaultSite.getId());
			loginNode.setRedisKey(redisKey);

			if (redisUtil.set(redisKey, loginNode, 3600L * 4) == false) {
				return JsonResult.noLogin();
			}

		} catch (Exception e) {
			e.printStackTrace();
			return JsonResult.noLogin();
		}
		if (null == loginNode || jsessionid == null) {
			return JsonResult.noLogin();
		}

		// 加入已更新
		addUpdatedAndReloginIdentification(loginNode);

		Map<String, Object> results = new HashMap<>();
		results.put("jsessionid", URLUtil.encode(jsessionid));
		results.put("loginUrl", loginNode.getLoginUrl());
		results.put("hostId", loginNode.getHost().getId());
		results.put("siteId", loginNode.getCurrentSiteId());
		return JsonResult.ok(results);
	}

	// 由于是重新登录过后，针对需要热更新部分的内容，进行加入已经更新操作
	void addUpdatedAndReloginIdentification(LoginNode loginNode) {
		identification.loginHostUpdated(loginNode.getHost().getId(), loginNode.getRedisKey());
		identification.loginRelogined(loginNode.getHost().getId(), loginNode.getRedisKey());
		identification.loginHostSetupUpdated(loginNode.getHost().getId(), loginNode.getRedisKey());
	}

	@Override
	public void tokenLogout() {
		Long hostId = requestHolder.getHost().getId();
		LoginNode loginNode = requestHolder.getCurrentLoginNode();
		String redisKey = loginNode.getRedisKey();
		String defalutHDomainHostKey = globalProperties.getNodeRedisKey().getDefalutHDomainHostKey(hostId);
		String siteListByHostId = globalProperties.getNodeRedisKey().getSiteListByHostId(hostId);
		redisUtil.del(redisKey);
		redisUtil.del(defalutHDomainHostKey);
		redisUtil.del(siteListByHostId);
	}

	@Override
	public LoginUser getLoginUser() {
		LoginNode loginNode = requestHolder.getCurrentLoginNode();
		if (loginNode == null || loginNode.getLoginUserId().longValue() < 1L) {
			return null;
		}

		LoginUser loginUser = new LoginUser(loginNode.getLoginUserId(), loginNode.getLoginUserName(), loginNode.getLoginUserType(), loginNode.getLogin35Mail(),
				loginNode.getLoginDomain(), loginNode.getRoles());
		return loginUser;
	}

	// 同步site
	@Override
	public void synchroSites(List<Site> sites) {
		if (!CollectionUtils.isEmpty(sites)) {
			for (Site site : sites) {
				RestResult sfondOne = nodeSiteFeign.findOne(site.getId());
				if (sfondOne.getCode() == 200) {
					// 修改
					nodeSiteFeign.updateById(site);
				} else if (sfondOne.getCode() == 401) {
					// 插入
					nodeSiteFeign.insert(site);
				} else {
					// 同步信息出错
					logger.error("同步 Site 信息出错: " + sfondOne.toString());
				}
			}
		}
	}

	@Override
	public boolean isAgent() {
		LoginNode loginNode = requestHolder.getCurrentLoginNode();
		if (loginNode == null) {
			return false;
		}
		LoginNodeAgent loginNodeAgent = loginNode.getLoginNodeAgent();
		if (loginNodeAgent == null) {
			return false;
		}
		int loginAgentDomain = loginNodeAgent.getLoginAgentDomain();
		return loginAgentDomain == 1;
	}

	@Override
	public void recacheLoginNode() {
		recacheLoginNode(requestHolder.getCurrentLoginNode());
	}

	@Override
	public void recacheLoginNode(LoginNode loginNode) {
		if (loginNode == null) {
			return;
		}
		String redisKey = loginNode.getRedisKey();
		redisUtil.set(redisKey, loginNode, redisUtil.getExpire(redisKey));
	}
}
